{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Portfolio Optimization using cvxpy"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Install cvxpy and other libraries"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "!{sys.executable} -m pip install -r requirements.txt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Imports"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cvxpy as cvx\n",
    "import numpy as np\n",
    "import quiz_tests_advanced"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Quiz Solution"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cvxpy as cvx\n",
    "import numpy as np\n",
    "\n",
    "def optimize_portfolio(returns, index_weights, scale=.00001):\n",
    "def optimize_portfolio(returns, index_weights, scale=.00001):\n",
    "    \"\"\"\n",
    "    Create a function that takes the return series of a set of stocks, the index weights,\n",
    "    and scaling factor. The function will minimize a combination of the portfolio variance\n",
    "    and the distance of its weights from the index weights.  \n",
    "    The optimization will be constrained to be long only, and the weights should sum to one.\n",
    "    \n",
    "    Parameters\n",
    "    ----------\n",
    "    returns : numpy.ndarray\n",
    "        2D array containing stock return series in each row.\n",
    "        \n",
    "    index_weights : numpy.ndarray\n",
    "        1D numpy array containing weights of the index.\n",
    "        \n",
    "    scale : float\n",
    "        The scaling factor applied to the distance between portfolio and index weights\n",
    "        \n",
    "    Returns\n",
    "    -------\n",
    "    x : np.ndarray\n",
    "        A numpy ndarray containing the weights of the stocks in the optimized portfolio\n",
    "    \"\"\"\n",
    "    m = returns.shape[0]\n",
    "    cov = np.cov(returns)\n",
    "    x = cvx.Variable(m)\n",
    "    portfolio_variance = cvx.quad_form(x, cov)\n",
    "    distance_to_index = cvx.norm(x - index_weights)\n",
    "    objective = cvx.Minimize(portfolio_variance + scale * distance_to_index)\n",
    "    constraints = [x >= 0, sum(x) == 1]\n",
    "    cvx.Problem(objective, constraints).solve()\n",
    "    x_values = x.value\n",
    "    return x_values\n",
    "\n",
    "quiz_tests_advanced.test_optimize_portfolio(optimize_portfolio)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
